/*
  1. 安装ts
    cnpm i typescript -g
  2. 编译ts
    tsc ./src/index.ts --outFile ./dist/index.js
  3. 初始化ts的配置文件
    tsc --init
  4. 实时监听
    tsc --watch
*/

// 定义字符串类型
let str: string = "hello";
console.log(str);
// 定义好类型的数据就不能修改成其他的类型了
// str = 5;
// 可以先定义，后赋值
let str2: string;
str2 = "world";
// 自动类型推断
let str3 = "zhangsan";

// 定义数字类型
let num: number = 3;
num = 5;

// 定义布尔值类型
let show: boolean = true;
show = false;

// 定义undefined类型
let udf: undefined = undefined;

// 定义null类型
let ul: null = null;

// 联合类型
let abc: number | string | boolean = 5;
abc = "5";
abc = true;

// const info: string | null = localStorage.getItem("userinfo");
// info && JSON.parse(info);

// 任意类型
let abc2: any = [1, 2, 3];
abc2 = { a: 3 };
abc2 = () => {};

// 数组类型
let arr: number[] = [1, 2, 3];
let arr2: Array<string> = ["a", "b", "c"];
let arr3: (number | string)[] = [1, "a", "c"];
let arr4: Array<number | boolean> = [1, true];

// 元组类型
// 特殊的数组，规定数组的长度，规定里面的每一项的数据类型
const arr5: [number, boolean] = [1, true];

// 对象类型
// 可以用，但是不能再做修改了
let obj: object = {
  name: "xiaohua",
  age: 20,
};

// 接口，给对象添加类型，语法和class差不多
interface Obj2type {
  name: string;
  age: number;
  // ?表示可选属性
  sex?: number;
  // 索引签名, 剩下的属性不知道还有什么，不关心有什么的时候可以使用
  [propname: string]: any;
}
let obj2: Obj2type = {
  name: "huaer",
  age: 21,
};
obj2.name = "bawanghua";
obj2.sex = 2;

interface Obj3Type {
  name: string;
  age: number;
  likes: string[];
}
let obj3: Obj3Type = {
  name: "shirenhua",
  age: 22,
  likes: ["买房", "炒股"],
};

interface ItemType {
  name: string;
  age: number;
}
let arr6: ItemType[] = [
  {
    name: "xiaohonghua",
    age: 23,
  },
  {
    name: "xiaoheihua",
    age: 24,
  },
];

interface RouteType {
  path: string;
  template: string;
  children?: RouteType[];
}
let arr7: RouteType[] = [
  {
    path: "/home",
    template: "<div>home</div>",
    children: [
      {
        path: "/home/home2",
        template: "<div>home2</div>",
      },
    ],
  },
  {
    path: "/about",
    template: "<div>about</div>",
  },
];

interface ChildrenType {
  child1: string;
  child2: string;
}
interface Obj4Type {
  name: string;
  age: number;
  children: ChildrenType;
}
let obj4: Obj4Type = {
  name: "dahua",
  age: 25,
  children: {
    child1: "xiaohua",
    child2: "xiaoxiaohua",
  },
};

// 枚举类型
// 类似于对象，不仅可以从key找到value，也可以从value找到key
enum Color {
  Red = 2,
  Green = 5,
  Bule = 8,
}
let g: Color = Color.Green;
console.log(g);
let b: string = Color[2];
console.log(b);


// 函数类型
// 函数的参数是不会做类型推断的
// 函数的类型表示返回值的类型
function fn(x: number, y: string): string {
  return x + y;
}
fn(3, "4");

const fn2: (x: number, y: number) => number = function (x: number, y: number): number {
  return x + y;
}

// void表示没有返回值
const fn3 = (): void => {
  console.log("fn3");
}

// never表示永不, 在死循环或者报错的时候用
const fn4 = (): never => {
  while (true) {}
}
const fn5 = () => {
  throw new Error("错误")
}

const fn6 = (x: number, y?: number): number => {
  return y ? x + y : x;
}
fn6(3)


// 泛型
// 可以将类型当作参数传给函数
function fn7<T>(x: T, y: T): number {
  return 3;
}
fn7<number>(3, 4);
// const count = ref<number>(3);

interface ObjType {
  name: string;
}
// class的类型
class Animal {
  constructor(obj: ObjType) {
    this.name = obj.name
  };
  name: string = "wangcai";
  sayName(): void {
    console.log(this.name);
  }
}
// 类的继承
class Dog extends Animal {
  // constructor是一个会被自动调用的函数,是在类被实例化的时候调用
  constructor(obj: ObjType) {
    super(obj);
    // console.log(obj);
  }
};
// 类的实例化
const dog = new Dog({
  name: "xiaohei"
});
console.log(dog.name);
dog.sayName()

